#!/bin/sh
#
# Copyright 2006-2007 Richard Hughes <richard@hughsie.com>
# Copyright 2007 Peter Jones <pjones@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.

# Handle video quirks.  If you are having suspend/resume issues,
# troubleshooting using this hook is probably the best place to start.
# If it weren't for video card quirks, suspend/resume on Linux would be 
# a whole lot more stable.

. "${PM_FUNCTIONS}"

for opt in $PM_CMDLINE; do
	case "${opt##--quirk-}" in # just quirks, please
		dpms-on) 	   QUIRK_DPMS_ON="true" ;;
		dpms-suspend) 	   QUIRK_DPMS_SUSPEND="true" ;;
		radeon-off) 	   QUIRK_RADEON_OFF="true" ;;
		reset-brightness)  QUIRK_RESET_BRIGHTNESS="true" ;;
		s3-bios) 	   QUIRK_S3_BIOS="true" ;;
		s3-mode) 	   QUIRK_S3_MODE="true" ;;
		vbe-post) 	   QUIRK_VBE_POST="true" ;;
		vbemode-restore)   QUIRK_VBEMODE_RESTORE="true" ;;
		vbestate-restore)  QUIRK_VBESTATE_RESTORE="true" ;;
		vga-mode3) 	   QUIRK_VGA_MODE_3="true" ;;
		no-fb) 		   QUIRK_NOFB="true" ;;
		pci-save) 	   QUIRK_PCI_SAVE="true" ;;
	        no-chvt)           QUIRK_NO_CHVT="true" ;;
		none) 		   QUIRK_NONE="true" ;;
		*) continue ;;
	esac
done

reset_brightness()
{
	for bl in /sys/class/backlight/* ; do
		[ -f "$bl/brightness" ] || continue
		BR="$(cat $bl/brightness)"
		echo 0 > "$bl/brightness"
		echo "$BR" > "$bl/brightness"
	done
}

if command_exists vbetool; then
	vbe() { vbetool "$@"; }
else 
	vbe() { echo "vbetool not installed!" 1>&2; return 1; }
fi

if command_exists radeontool; then
	radeon() { radeontool "$@"; }
else 
	radeon() { echo "radeontool not found" 1>&2; return 1; }
fi

die_if_framebuffer() 
{ 
	[ -d "/sys/class/graphics/fb0" ] || return
	echo "--quirk-no-fb passed, but system is using a framebuffer."
	echo "Aborting."
	exit 1
}


save_fbcon()
{
	local con
	for con in /sys/class/graphics/*/state; do
		[ -f $con ] || continue
		echo 1 >"${con}"
	done
}

resume_fbcon()
{
	local con
	for con in /sys/class/graphics/*/state; do
		[ -f $con ] || continue
		echo 0 >"${con}"
	done
}

maybe_chvt()
{
    [ "$QUIRK_NO_CHVT" = "true" ] && return
    fgconsole |savestate console
    chvt 63
}

maybe_deallocvt()
{
    [ "$QUIRK_NO_CHVT" = "true" ] && return
    state_exists console || return
    chvt $(restorestate console)
    deallocvt 63
}

# Some tiny helper functions for quirk handling
quirk() { [ "$1" = "true" ] && [ -z $QUIRK_NONE ]; }

# save/restore vbe state
vbe_savestate() { vbe vbestate save |savestate vbestate; }
vbe_restorestate() { restorestate vbestate |vbe vbestate restore; }

# save/restore the vbe mode
vbe_savemode() { vbe vbemode get |savestate vbemode; }
vbe_restoremode() 
{
	# this is a little mode complicated to handle special-casing mode 3.
	local vbemode=$(restorestate vbemode)
	if [ "$vbemode" = "3" ]; then
		vbe vgamode set $vbemode
	else 
		vbe vbemode set $vbemode
	fi
}

# post the video card
vbe_post() 
{
	local rom="/var/run/video.rom"
	# if we do not have a romfile, do not post with it.
	[ -f "$rom" ] || unset rom
	vbe post $rom
	sleep 0.1 
}

# turn critical bits of radeon cards off/on
radeon_off() { radeon dac off; radeon light off; }
radeon_on() { radeon dac on; radeon light on; }

# save and restore video card PCI config state
save_pci() 
{
	local pci="/sys/bus/pci/devices"
	for dev in "${pci}"/*; do
		[ -f "${dev}/class" ] || continue
		[ $(cat "${dev}/class") = "0x030000" ] || continue
		[ -f "${dev}/config" ] || continue
		# it is a video card, it has a configuration.  Save it.
		savestate "pci_video_${dev##*/}" <${dev}/config
	done
}

restore_pci() 
{
	local pci="/sys/bus/pci/devices"
	for dev in "${pci}"/*; do
		state_exists "pci_video_${dev##*/}" || continue
		restorestate "pci_video_${dev##*/}" > "${dev}/config"
	done
}

suspend_video()
{
	# 0=nothing, 1=s3_bios, 2=s3_mode, 3=both
	local acpi_flag=0
	quirk "${QUIRK_S3_BIOS}" && 		acpi_flag=$(($acpi_flag + 1))
	quirk "${QUIRK_S3_MODE}" && 		acpi_flag=$(($acpi_flag + 2))
	sysctl -w kernel.acpi_video_flags=$acpi_flag
	
	quirk "${QUIRK_NOFB}" && 		die_if_framebuffer
	quirk "${QUIRK_VBESTATE_RESTORE}" && 	vbe_savestate
	quirk "${QUIRK_VBEMODE_RESTORE}" && 	vbe_savemode
	quirk "${QUIRK_RADEON_OFF}" && 		radeon_off
	quirk "${QUIRK_PCI_SAVE}" && 		pci_save
	quirk "${QUIRK_VGA_MODE_3}" && 		vbe vbemode set 3
	quirk "${QUIRK_DPMS_SUSPEND}" && 	vbe dpms suspend
	save_fbcon
}
resume_video()
{
	# We might need to do one or many of these quirks
	quirk "${QUIRK_PCI_SAVE}" && 		pci_restore
	quirk "${QUIRK_VBE_POST}" && 		vbe_post
	quirk "${QUIRK_VBESTATE_RESTORE}" && 	vbe_restorestate
	quirk "${QUIRK_VBEMODE_RESTORE}" && 	vbe_restoremode
	resume_fbcon 	# also should be handled by a quirk.
	quirk "${QUIRK_RADEON_OFF}" && 		radeon_on
	quirk "${QUIRK_DPMS_ON}" && 		vbe dpms on
	quirk "${QUIRK_RESET_BRIGHTNESS}" && 	reset_brightness
	return 0  # avoid spurious hook exit failure message.
}

help() {
	echo  # first echo makes it look nicer.
	echo "Video quirk handler options:"
	echo
	echo "  --quirk-dpms-on"
	echo "  --quirk-dpms-suspend"
	echo "  --quirk-radeon-off"
	echo "  --quirk-reset-brightness"
	echo "  --quirk-s3-bios"
	echo "  --quirk-s3-mode"
	echo "  --quirk-vbe-post"
	echo "  --quirk-vbemode-restore"
	echo "  --quirk-vbestate-restore"
	echo "  --quirk-vga-mode3"
	echo "  --quirk-none"
}

case "$1" in
	suspend) maybe_chvt; suspend_video ;;
	hibernate) maybe_chvt
		if [ "$HIBERNATE_RESUME_POST_VIDEO" = "yes" ]; then
			suspend_video
		fi
		;;
	resume) resume_video; maybe_deallocvt;;
	thaw)
		if [ "${HIBERNATE_RESUME_POST_VIDEO}" = "yes" ]; then
			resume_video
		fi
		maybe_deallocvt
		;;
	help) help ;;
esac
